﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace MessengerBot
{
    /// <summary>
    /// This class holds the configuration for a <see cref="Bot"/> object.
    /// </summary>
    public sealed class BotConfiguration
    {
        /// <summary>
        /// This is the backing field for the <see cref="Systems"/> property.
        /// </summary>
        private readonly HashSet<ISystem> _Systems = new HashSet<ISystem>();

        /// <summary>
        /// This is the backing field for the <see cref="IsFrozen"/> property.
        /// </summary>
        private bool _IsFrozen;

        /// <summary>
        /// This is the backing field for the <see cref="Password"/> property.
        /// </summary>
        private string _Password;

        /// <summary>
        /// This is the backing field for the <see cref="Username"/> property.
        /// </summary>
        private string _Username;

        /// <summary>
        /// Initializes a new instance of the <see cref="BotConfiguration"/> class.
        /// </summary>
        public BotConfiguration()
        {
            AddSystem(new HelpSystem());
        }

        /// <summary>
        /// Gets or sets the <see cref="ILogger"/> to log to during execution.
        /// </summary>
        public ILogger Logger
        {
            get;

            set;
        }

        /// <summary>
        /// Gets or sets the username to use when authenticating with the Windows Live Messenger servers.
        /// </summary>
        public string Username
        {
            get
            {
                return _Username;
            }

            set
            {
                string fixedValue = (value ?? string.Empty).Trim();
                if (fixedValue != _Username)
                {
                    if (_IsFrozen)
                        throw new InvalidOperationException("BotConfiguration is frozen, cannot change username");

                    _Username = fixedValue;
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether this <see cref="BotConfiguration"/> instance has been frozen,
        /// preventing further changes to its contents.
        /// </summary>
        public bool IsFrozen
        {
            get
            {
                return _IsFrozen;
            }
        }

        /// <summary>
        /// Gets or sets the password to use when authenticating with the Windows Live Messenger servers,
        /// that is associated with the <see cref="BotConfiguration.Username"/>.
        /// </summary>
        public string Password
        {
            get
            {
                return _Password;
            }

            set
            {
                string fixedValue = (value ?? string.Empty).Trim();
                if (fixedValue != _Username)
                {
                    if (_IsFrozen)
                        throw new InvalidOperationException("BotConfiguration is frozen, cannot change password");

                    _Password = fixedValue;
                }
            }
        }

        /// <summary>
        /// Gets a collection of all the <see cref="ISystem"/> objects registered with this
        /// <see cref="BotConfiguration"/>.
        /// </summary>
        public IEnumerable<ISystem> Systems
        {
            get
            {
                foreach (ISystem system in _Systems)
                    yield return system;
            }
        }

        /// <summary>
        /// Freezes this <see cref="BotConfiguration"/> instance, preventing further changes to it.
        /// </summary>
        public void Freeze()
        {
            _IsFrozen = true;
        }

        /// <summary>
        /// Validates the contents and integrity of this <see cref="BotConfiguration"/> object.
        /// </summary>
        /// <exception cref="InvalidOperationException">
        /// <para>This <see cref="BotConfiguration"/> instance is incomplete or in an invalid state.</para>
        /// </exception>
        public void Validate()
        {
            if (Username.Length == 0)
                throw new InvalidOperationException("Need username for authentication purposes");
            if (Password.Length == 0)
                throw new InvalidOperationException("Need password for authentication purposes");
        }

        /// <summary>
        /// Adds a bot sub-system responsible for processing commands to this
        /// <see cref="BotConfiguration"/>.
        /// </summary>
        /// <param name="system">
        /// The <see cref="ISystem"/> implementation that should be added.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <para><paramref name="system"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// <para><paramref name="system"/> was already registered.</para>
        /// </exception>
        public void AddSystem(ISystem system)
        {
            if (system == null)
                throw new ArgumentNullException("system");
            if (_Systems.Contains(system))
                throw new InvalidOperationException("System has already been registered");

            _Systems.Add(system);
        }
    }
}